﻿using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading;
using System;

#region  多线程执行

//class JobFileTextSearchReplace
//{
//    private string m_Path;
//    private List<string> m_Patterns;
//    private string m_ReplaceStr;
//    private bool[] m_SearchRet;

//    public ManualResetEvent doneEvent;
//    public string exception;

//    public JobFileTextSearchReplace(string path, List<string> patterns, string replaceStr, bool[] searchRet)
//    {
//        m_Path = path;
//        m_Patterns = patterns;
//        m_ReplaceStr = replaceStr;
//        m_SearchRet = searchRet;
//        doneEvent = new ManualResetEvent(false);
//    }

//    public void ThreadPoolCallback(System.Object threadContext)
//    {
//        try
//        {
//            string text = File.ReadAllText(m_Path);

//            ///
//        }
//        catch (Exception ex)
//        {
//            exception = m_Path + "\n" + ex.Message;
//        }

//        doneEvent.Set();
//    }


//protected void ThreadDoFilesTextSearchReplace(List<string> fileList, List<string> patterns, string replaceStr, bool[][] searchRetList)
//{
//    List<JobFileTextSearchReplace> jobList = new List<JobFileTextSearchReplace>();
//    List<ManualResetEvent> eventList = new List<ManualResetEvent>();

//    int numFiles = fileList.Count;
//    int numFinished = 0;
//    AssetDanshariUtility.DisplayThreadProgressBar(numFiles, numFinished);

//    int timeout = 600000;  // 10 分钟超时

//    for (var i = 0; i < fileList.Count; i++)
//    {
//        JobFileTextSearchReplace job = new JobFileTextSearchReplace(fileList[i], patterns, replaceStr, searchRetList[i]);
//        jobList.Add(job);
//        eventList.Add(job.doneEvent);
//        ThreadPool.QueueUserWorkItem(job.ThreadPoolCallback);

//        if (eventList.Count >= Environment.ProcessorCount)
//        {
//            WaitForDoFile(eventList, timeout);
//            AssetDanshariUtility.DisplayThreadProgressBar(numFiles, numFinished);
//            numFinished++;
//        }
//    }

//    while (eventList.Count > 0)
//    {
//        WaitForDoFile(eventList, timeout);
//        AssetDanshariUtility.DisplayThreadProgressBar(numFiles, numFinished);
//        numFinished++;
//    }

//    foreach (var job in jobList)
//    {
//        if (!string.IsNullOrEmpty(job.exception))
//        {
//            Debug.LogError(job.exception);
//        }
//    }
//}

//private void WaitForDoFile(List<ManualResetEvent> events, int timeout)
//{
//    int finished = WaitHandle.WaitAny(events.ToArray(), timeout);
//    if (finished == WaitHandle.WaitTimeout)
//    {
//        // 超时
//    }
//    events.RemoveAt(finished);
//}
//}

#endregion
public class FindReferences
{
    static private int startIndex;
    private static string targetUUID;
    private static string[] files;
    private static List<string> withoutExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };
    private static object locker = new object();//创建锁
    public delegate void ParameterizedThreadStart(int pStartIndex,int pEndIndex);
    private static int threadEndRemind;
    private static int maxThreadCount = 4;
    private static Thread[] threadArray;
    private static string resultInfo;

    [MenuItem("Assets/Find References", false, 10)]
    static private void Find()
    {
        EditorSettings.serializationMode = SerializationMode.ForceText;
        string path = AssetDatabase.GetAssetPath(Selection.activeObject);
        if (!string.IsNullOrEmpty(path))
        {
            targetUUID = AssetDatabase.AssetPathToGUID(path);
            files = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories)
                .Where(s => withoutExtensions.Contains(Path.GetExtension(s).ToLower())).ToArray();

            if(files.Length == 0)
            {
                Debug.Log("no file to search");
                return;
            }
            startIndex = 0;
            resultInfo = "";
            int threadCount = Mathf.Min(files.Length, maxThreadCount);
            threadEndRemind = threadCount;
            threadArray = new Thread[threadCount];
            int space = Mathf.FloorToInt(files.Length / threadCount);
            for (int i = 0; i < threadCount; i++)
            {
                int start = i * space;
                int end ;
                if(i == threadCount - 1)
                {
                    end = files.Length - 1;
                }
                else
                {
                    end = start + space - 1;
                }
                
                //Debug.Log(start + " " + end + " " + files.Length);
                threadArray[i] = new Thread(() => {
                    FindInOneFile(start, end);
                });
                threadArray[i].Start();
            }
           
        }
    }
    public delegate void ProcessDelegate();
    static ProcessDelegate showProcess = new ProcessDelegate(ProcessShow);
    public static void ProcessShow()
    {
        EditorUtility.DisplayCancelableProgressBar("匹配资源中", startIndex.ToString(),(float)startIndex / (float)files.Length);
    }

    private static void FindEnd()
    {
        Debug.Log("find end ======================");
        Debug.Log(resultInfo);
    }
    private static void FindInOneFile(int pStartIndex, int pEndIndex)
    {
        //lock (locker)
        //{
            
            int subStart = pStartIndex;
            int subLen = pEndIndex - pStartIndex + 1;
            while (pStartIndex <= pEndIndex)
            {
                string file = files[pStartIndex];
                //string log = string.Format("匹配资源中 {0} {1} / {2}",  file, pStartIndex , subLen);
                //Debug.Log(log);
                //EditorUtility.DisplayCancelableProgressBar("匹配资源中", file, (float)startIndex / (float)files.Length);
                if (Regex.IsMatch(File.ReadAllText(file), targetUUID))
                {
                //Debug.Log(file, AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(file)));
                    //Debug.Log("finded " + file);
                    resultInfo += file + "\n";
                }
                pStartIndex++;
                if (pStartIndex > pEndIndex)
                {
                    //EditorUtility.ClearProgressBar();
                    threadEndRemind--;
                    if (threadEndRemind == 0)
                    {
                        FindEnd();
                    }
                    Thread.CurrentThread.Abort();
                    return;
                }
        }
        //}
    }

    [MenuItem("Assets/Find References", true)]
    static private bool VFind()
    {
        string path = AssetDatabase.GetAssetPath(Selection.activeObject);
        return (!string.IsNullOrEmpty(path));
    }

    static private string GetRelativeAssetsPath(string path)
    {
        return "Assets" + Path.GetFullPath(path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
    }
}